﻿using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Interceptors;
using K9Nano.Share.Exceptions;

namespace K9Nano.RemoteServer
{
    public class DefaultServerInterceptor : Interceptor
    {
        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context,
            BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            try
            {
                return base.BlockingUnaryCall(request, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context,
            AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            try
            {
                return base.AsyncUnaryCall(request, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request,
            ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            try
            {
                return base.AsyncServerStreamingCall(request, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context,
            AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            try
            {
                return base.AsyncClientStreamingCall(context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context,
            AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            try
            {
                return base.AsyncDuplexStreamingCall(context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                { 
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context,
            UnaryServerMethod<TRequest, TResponse> continuation)
        {
            try
            {
                return await base.UnaryServerHandler(request, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override async Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context,
            ClientStreamingServerMethod<TRequest, TResponse> continuation)
        {
            try
            {
                return await base.ClientStreamingServerHandler(requestStream, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override async Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream,
            ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
        {
            try
            {
                await base.ServerStreamingServerHandler(request, responseStream, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }

        public override async Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream,
            IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
        {
            try
            {
                await base.DuplexStreamingServerHandler(requestStream, responseStream, context, continuation);
            }
            catch (K9UserFriendlyException ex)
            {
                var meta = new Metadata
                {
                    {"code", ex.Code.ToString()},
                    {"error", ex.Message}
                };
                throw new RpcException(new Status(StatusCode.Unknown, ex.Message), meta);
            }
        }
    }
}